# 作者：yjh2011@live.com
# 功能：根据给定的若干篇文献寻找相关领域的重要作者
# 输入：list<文章名称>
# 输出：list<作者，分数>

import requests
import pandas as pd
import numpy as np
from bs4 import BeautifulSoup
from collections import Counter
import logging

def loggingSetup(isDebug=False):
    '''
        配置日志
    '''
    if(isDebug):
        level=logging.DEBUG
    else:
        level=logging.INFO
    logging.basicConfig(level=level,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='myapp.log',
                    filemode='w')
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    formatter = logging.Formatter('%(levelname)-8s %(message)s')
    console.setFormatter(formatter)
    logging.getLogger('').addHandler(console)

class URLHelper():
    headers={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'}
    
    def BSHTTPGET(URL):
        logging.debug("HTTPGET: %s" % URL)
        res=requests.get(URL,headers=URLHelper.headers)
        return BeautifulSoup(res.text, "html.parser")
    
    def getQueryURL(title):
        # "https://cn.bing.com/academic/profile?id=3f4ce6e5867a01f9d2e858bbd0c5d88a&encoded=0&v=paper_preview&mkt=zh-cn&mkt=zh-CN"
        return "https://www.bing.com/academic/search?q="+title.replace(' ','+')+"&qs=n&form=QBRE&sp=-1&pq=emission+characteristics+and+variation+of+volatile+odorous+compounds+in+the+initial+decomposition+stage+of+municipal+solid+waste&sc=0-128&sk=&cvid=25AA8FB79CB845A690767F2517E24491&mkt=zh-CN"
    
    def getProfileURL(pid):
        # "https://cn.bing.com/academic/profile?id=3f4ce6e5867a01f9d2e858bbd0c5d88a&encoded=0&v=paper_preview&mkt=zh-cn&mkt=zh-CN"
        return "https://cn.bing.com/academic/profile?id="+pid+"&encoded=0&v=paper_preview&mkt=zh-cn&mkt=zh-CN"
    
    def getRefURL(pid):
        # "https://cn.bing.com/academic/papers?ajax=scroll&infscroll=1&id=3f4ce6e5867a01f9d2e858bbd0c5d88a&encoded=0&v=paper_preview&mkt=zh-cn&mkt=zh-CN&first=0&count=100&IG=C9C6B7A307DB49F9B882C26040B8EEEF&IID=morepage.1&SFX=1&rt=1"
        return "https://cn.bing.com/academic/papers?ajax=scroll&infscroll=1&id="+pid+"&encoded=0&v=paper_preview&mkt=zh-cn&mkt=zh-CN&first=0&count=100&IG=C9C6B7A307DB49F9B882C26040B8EEEF&IID=morepage.1&SFX=1&rt=1"

class ScoreHelper():
    def getAuthorsScore(n):
        res=[1,1]
        if(n>2):
            res+=[1/(i+1) for i in range(n-2)]
        return res[:n]

    def authorList2DF(authors):
        df0=pd.DataFrame()
        for author in authors:
            df=pd.DataFrame({
                'author':author,
                'score':ScoreHelper.getAuthorsScore(len(author))
            })
            df0=df0.append(df)
        return df0

    def getValuableAuthors(df,n=5):
        df = df.groupby(df['author']).sum()
        df=df.sort_values(['score'],ascending=False)
        return df[:n]
        
class Article():
    def __init__(self):
        self.title=""
        self.author=[]
        self.refByTitle=[]
        self.refByArticle=[]
        self._level=0
        self.errmsg=""
    
    def getTitles(self,repeat=False):
        titles=[]
        authors=[]
        if(self.title!=""):
            titles=[self.title]
            authors=[self.author]
        if(self._level>0):
            for item in self.refByArticle:
                tmpTitle,tmpAuthors = item.getTitles(repeat)
                for i in range(len(tmpTitle)):
                    if(repeat or tmpTitle[i] not in titles):
                        titles+=[tmpTitle[i]]
                        authors+=[tmpAuthors[i]]
        return titles, authors
    
    def retrieve(self,n=1):
        if(n==0):
            return
        if(self._level==0):
            logging.info("[%d]个项目等待检索" % len(self.refByTitle))
            self.refByArticle=[getArticleByTitle(title) for title in self.refByTitle]
            for item in self.refByArticle:
                item.retrieve(n-1)
        else:
            for item in self.refByArticle:
                item.retrieve(n)
        self._level+=n

def getArticleByTitle(title):
    logging.info("文章："+title)

    # 查询文章
    queryURL=URLHelper.getQueryURL(title)
    soup=URLHelper.BSHTTPGET(queryURL)

    # 检测是否找到文章
    notFoundErr=False
    
    # 如果页面显示没有
    chk=soup.select('.aca_noresult p')
    if(len(chk)>0 and chk[0].text[:2]=="抱歉"):
        notFoundErr=True
    else:
        # 如果找不到准确文章
        chk=soup.select('li.aca_algo a')[0].get('href')[:21]
        if(chk!="/academic/profile?id="):
            notFoundErr=True

    # 报错信息
    if(notFoundErr):
        res=Article()
        res.title="err"
        res.errmsg="文章未找到："+queryURL
        logging.warning(res.errmsg)
        return res

    # 获取文章id
    pid=soup.select('li.aca_algo a')[0].get('href')[21:].split('&')[0]

    # 收集文章信息
    profURL=URLHelper.getProfileURL(pid)
    soup = URLHelper.BSHTTPGET(profURL)

    # 构建文章信息
    res = Article()
    res.title=soup.select('.aca_title')[0].text
    res.author=[item.text for item in soup.select('.aca_desc.b_snippet a[target]')]

    # 收集引用信息
    refURL=URLHelper.getRefURL(pid)
    soup = URLHelper.BSHTTPGET(refURL)

    # 构建引用信息
    res.refByTitle=[item.text for item in soup.select('a')]
    logging.info("作者：[%d] %s" % (len(res.author),", ".join(res.author)))
    return res

def FindTheAuthor(titles,n=2):
    if(titles==[]):
        print("至少输入一个文章题目")
        return
    loggingSetup()
    a=Article()
    a.title=""
    a.refByTitle=titles
    a.retrieve(n)
    titles, authors = a.getTitles()
    df=ScoreHelper.authorList2DF(authors)
    res=ScoreHelper.getValuableAuthors(df)
    print(res)

######################
# 仅用于测试
######################
# 样例一
######################
# titles=[
#     "Parameter sensitivity to concentrations and transport distance of odorous compounds from solid waste facilities",
#     "Statistical correlations on the emissions of volatile odorous compounds from the transfer stage of municipal solid waste",
#     "Emission characteristics and variation of volatile odorous compounds in the initial decomposition stage of municipal solid waste"
# ]
######################
# 样例二
######################
# titles=[
#     "Evaluation of the chemical composition and correlation between the calculated and measured odour concentration of odorous gases from a landfill in Beijing, China",
#     "Environmental monitoring and fuzzy synthetic evaluation of municipal solid waste transfer stations in Beijing in 2001–2006",
#     "Measuring odours in the environment vs. dispersion modelling: A review",
#     "Emission characteristics and health risk assessment of volatile organic compounds produced during municipal solid waste composting"
# ]
######################
# 你需要查询的文献
titles=[
    "Brain plasticity and behavior in depression: Gene and environment studies"
]
FindTheAuthor(titles,n=2)